package com.zzw.interceptor;

import com.zzw.common.ApiCommonResponse;
import com.zzw.constant.OrderConstant;
import com.zzw.properties.InterceptorCommonsProperties;
import com.zzw.properties.RedisRateLimterProperties;
import com.zzw.ratelimter.RateLimiter;
import com.zzw.ratelimter.RedisRateLimiter;
import com.zzw.requestcontext.RequestContext;
import com.zzw.utils.JsonHelper;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author Administrator
 */
public class RedisRateLimterInterceptor implements InternalHandlerInterceptor {

    private static final Logger logger = LoggerFactory.getLogger(RedisRateLimterInterceptor.class);

    private final RedisRateLimterProperties interceptorCommonsProperties;
    private final RedisRateLimiter redisRateLimiter;

    public RedisRateLimterInterceptor(RedisRateLimterProperties interceptorCommonsProperties, RedisRateLimiter redisRateLimiter) {
        this.interceptorCommonsProperties = interceptorCommonsProperties;
        this.redisRateLimiter = redisRateLimiter;
    }

    @Override
    public int getOrder() {
        return OrderConstant.REQUEST_REDIS_RATELIMTER_ORDER;
    }

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestHeaderKey = interceptorCommonsProperties.getRequestHeaderKey();
        if (StringUtils.isNotBlank(requestHeaderKey)) {
            RateLimiter.Response allowed = redisRateLimiter.isAllowed(requestHeaderKey);
            if (!allowed.isAllowed()) {
                RequestContext requestContext = RequestContext.getInstance();
                logger.error("the request is limit,header key is:{},ip:{},rate limter is :{},bucket count is:{}", requestHeaderKey, requestContext.getIp()
                        , interceptorCommonsProperties.getReplenishRate(), interceptorCommonsProperties.getBurstCapacity());
                response.setHeader("Content-Type", MediaType.APPLICATION_JSON.toString());
                response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());
                response.getWriter().println(JsonHelper.toJson(ApiCommonResponse.of(requestContext.getSn()
                        , "" + HttpStatus.TOO_MANY_REQUESTS.value(), HttpStatus.TOO_MANY_REQUESTS.getReasonPhrase())));
                return false;
            }
        }
        return InternalHandlerInterceptor.super.preHandle(request, response, handler);
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        InternalHandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        InternalHandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }

    @Override
    public InterceptorCommonsProperties getInterceptorCommonsProperties() {
        return interceptorCommonsProperties;
    }
}
